<?xml version="1.0" encoding="UTF-8" ?>
<!--
	SPARQL XML -> SPARQL JSON
	Created by Keith Alexander on 2008-01-27.
-->

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
				xmlns:s="http://www.w3.org/2005/sparql-results#">

	<xsl:output encoding="UTF-8" indent="yes" method="text" />

	<xsl:template match="/">
		<xsl:apply-templates />
	</xsl:template>
	
	<xsl:template match="s:sparql">
		{<xsl:apply-templates />}
	</xsl:template>
	
	<xsl:template match="s:head">
		"head": { 
		    "link" : [<xsl:apply-templates select="s:link" />],
			"vars": [<xsl:apply-templates select="s:variable"/>]
		},
	</xsl:template>
	<xsl:template match="s:link">"<xsl:value-of select="@href"/>" <xsl:if test="position()!=last()">,</xsl:if>
	</xsl:template>	
	
	<xsl:template match="s:variable">"<xsl:value-of select="@name"/>" <xsl:if test="position()!=last()">,</xsl:if>
	</xsl:template>
	
	<xsl:template match="s:results">
		"results": { "bindings": [<xsl:apply-templates />]}
	</xsl:template>
	<xsl:template match="s:result">
		{<xsl:apply-templates />}<xsl:if test="position()!=last()">,</xsl:if>
	</xsl:template>
	<xsl:template match="s:binding">
		"<xsl:value-of select="@name"/>": {
			"value": <xsl:call-template name="escape-string"><xsl:with-param name="s"><xsl:value-of select="./*"/></xsl:with-param></xsl:call-template>,
			<xsl:apply-templates select="./*"/>
		 }<xsl:if test="position()!=last()">,</xsl:if>
	</xsl:template>
	<xsl:template match="s:literal[@datatype]">"type": "typed-literal",
		"datatype": "<xsl:value-of select="@datatype"/>",
	</xsl:template>
	<xsl:template match="s:literal[@xml:lang]">"type": "literal",
		"xml:lang": "<xsl:value-of select="@xml:lang"/>",
	</xsl:template>
	<xsl:template match="s:literal">"type": "literal",</xsl:template>
	<xsl:template match="s:uri">"type": "uri",</xsl:template>
	<xsl:template match="s:bnode">"type": "bnode",</xsl:template>
	<xsl:template match="s:boolean">"boolean": <xsl:apply-templates/>,</xsl:template>
	

<!-- Escape string functions pinched from  http://code.google.com/p/xml2json-xslt/ -->
  <xsl:template name="escape-string">
    <xsl:param name="s"/>
    <xsl:text>"</xsl:text>
    <xsl:call-template name="escape-bs-string">
      <xsl:with-param name="s" select="$s"/>
    </xsl:call-template>
    <xsl:text>"</xsl:text>
  </xsl:template>

  <!-- Escape the backslash (\) before everything else. -->
  <xsl:template name="escape-bs-string">
    <xsl:param name="s"/>
    <xsl:choose>
      <xsl:when test="contains($s,'\')">
        <xsl:call-template name="escape-quot-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'\'),'\\')"/>
        </xsl:call-template>
        <xsl:call-template name="escape-bs-string">
          <xsl:with-param name="s" select="substring-after($s,'\')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="escape-quot-string">
          <xsl:with-param name="s" select="$s"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Escape the double quote ("). -->
  <xsl:template name="escape-quot-string">
    <xsl:param name="s"/>
    <xsl:choose>
      <xsl:when test="contains($s,'&quot;')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'&quot;'),'\&quot;')"/>
        </xsl:call-template>
        <xsl:call-template name="escape-quot-string">
          <xsl:with-param name="s" select="substring-after($s,'&quot;')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="$s"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Replace tab, line feed and/or carriage return by its matching escape code. Can't escape backslash
       or double quote here, because they don't replace characters (&#x0; becomes \t), but they prefix 
       characters (\ becomes \\). Besides, backslash should be seperate anyway, because it should be 
       processed first. This function can't do that. -->
  <xsl:template name="encode-string">
    <xsl:param name="s"/>
    <xsl:choose>
      <!-- tab -->
      <xsl:when test="contains($s,'&#x9;')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'&#x9;'),'\t',substring-after($s,'&#x9;'))"/>
        </xsl:call-template>
      </xsl:when>
      <!-- line feed -->
      <xsl:when test="contains($s,'&#xA;')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'&#xA;'),'\n',substring-after($s,'&#xA;'))"/>
        </xsl:call-template>
      </xsl:when>
      <!-- carriage return -->
      <xsl:when test="contains($s,'&#xD;')">
        <xsl:call-template name="encode-string">
          <xsl:with-param name="s" select="concat(substring-before($s,'&#xD;'),'\r',substring-after($s,'&#xD;'))"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise><xsl:value-of select="$s"/></xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>